%include "macroses.inc"

global PrintString
global PrintDecimal
global Fprintf

;| input
;rax == string
;rdi == fd
;| output rax == number written chars
PrintString:
    push rbx
    xor rbx, rbx
    .next_iter:
        cmp [rax + rbx], byte 0x0
        je .ret
        PRINT_CHAR [rax + rbx], rdi
        inc rbx
        jmp .next_iter

    .ret:
        mov rax, rbx
        pop rbx
        ret

;| input
;rax == hex
;rdi == fd
;| output
;rax == number writtern chars
PrintHex:
    push rcx
    push rbx
    push rdx

    xor rcx, rcx

    .next_iter:
        mov rbx, 16
        xor rdx, rdx
        div rbx
        push rdx
        inc rcx
        cmp rax, 0x0
        je .print_iter
        jmp .next_iter

    .print_iter:
        xor rdx, rdx
        mov rbx, rcx
        cmp rcx, 0
        je .close
        .print_loop:
            pop rax
            cmp rax, 9
            ja .print_hex
            jmp .print_dec
            
            .print_hex:
                mov rdx, 15
                sub rdx, rax
                PRINT_CHAR [hex+rdx], rdi
                loop .print_loop
                jmp .close

            .print_dec:  
                add rax, '0'
                PRINT_CHAR rax, rdi
                loop .print_loop
                jmp .close

    .close:
        mov rax, rbx

        pop rdx 
        pop rbx
        pop rcx

        ret

    hex db 'FEDCBA'

;| input
;rax == number
;rdi == fd
;| output
;rax == number written chars
PrintDecimal:
    push rcx
    push rbx
    push rdx

    xor rcx, rcx

    cmp rax, 0
    jl .is_minus
    jmp .next_iter
    
    .is_minus:
        neg rax
        PRINT_CHAR '-', rdi

    .next_iter:
        mov rbx, 10
        xor rdx, rdx
        div rbx
        push rdx
        inc rcx
        cmp rax, 0x0
        je .print_iter
        jmp .next_iter

    .print_iter:
        mov rbx, rcx
        cmp rcx, 0
        je .close
        .print_loop:
            pop rax
            add rax, '0'
            PRINT_CHAR rax, rdi
            loop .print_loop
        jmp .close

    .close:
        mov rax, rbx

        pop rdx 
        pop rbx
        pop rcx

        ret


;| input:
;rdi == fd
;rax == format
;values == stack
;| output:
;rax == count
Fprintf:
    push rbp
    mov rbp, rsp

    push rbx
    push rcx
    push rdi
    
    xor rbx, rbx
    xor rcx, rcx
    .next_iter:
        cmp [rax], byte 0
        je .ret

        cmp [rax], byte '%'
        je .special_char

        jmp .default_char
        
        .special_char:
            inc rax

            cmp [rax], byte 's'
            je .print_string

            cmp [rax], byte 'd'
            je .print_decimal

            cmp [rax], byte 'c'
            je .print_char

            cmp [rax], byte 'x'
            je .print_hex

            cmp [rax], byte '%'
            je .default_char

            jmp .is_error

        .print_string:
            push rax

            mov rax, [next_arg]
            call PrintString
            add rcx, rax

            pop rax
            inc rbx
            jmp .next_step

        .print_hex:
            push rax

            mov rax, [next_arg]
            call PrintHex
            add rcx, rax

            pop rax
            inc rbx
            jmp .next_step

        .print_char:
            push rax

            mov rax, [next_arg]
            PRINT_CHAR [rax], rdi
            inc rcx

            pop rax
            inc rbx
            jmp .next_step

        .print_decimal:
            push rax

            mov rax, [next_arg]
            call PrintDecimal
            add rcx, rax 

            pop rax
            inc rbx
            jmp .next_step

        .default_char:
            PRINT_CHAR [rax], rdi
            inc rcx
        
        .next_step:
            inc rax
            jmp .next_iter

        .is_error:
            PRINT_CHAR '%', rdi
            inc rcx
            jmp .default_char

    .ret:
        mov rax, rcx
        pop rdi
        pop rcx
        pop rbx
        pop rbp
        ret
    
